﻿/*------------------------------------------------------------------------

CXXLCOMPOSITE.HPP v3.6

Copyright 楊志賢 CxxlMan, 2011 - 2014
All Rights Reserved

------------------------------------------------------------------------*/
#if !defined(__CXXLCOMPOSITE_HPP_CxxlMan)
#define __CXXLCOMPOSITE_HPP_CxxlMan

#include <string>
#include "GUID.HPP"
#include "CXXLAVLTREE.HPP"
#include "SMART_STRING.HPP"

#if defined(_CXXLCONTAINER_DLLEXPORT)
#define CXXLCONTAINER_DLLEXPORT CXXL_DLLEXPORT
#else
#define CXXLCONTAINER_DLLEXPORT CXXL_DLLIMPORT
#endif

// 節點名稱不能含有這個子字串
#define COMPOSITERESERVEIDNAME L"←┼→"

namespace CxxlMan
{

/*
  T = 要包裝的物件型別，須是 cxxlObject 的延伸類別
  isUnique = 子節點的名稱不可重複設為 true，否則為 false
*/
template <typename T, bool isUnique>
class cxxlComposite:virtual public cxxlObject
{

  // 存放子節點，Key 為子節點的名稱，以方便快速巡找
  class Search_Tree:public cxxlAVL_Tree<cxxlComposite<T,isUnique>, UNICODE_String, isUnique>
  {
    bool cxxlFASTCALL isLeftAt(UNICODE_String O_Key,UNICODE_String addKey) const
    {
      return O_Key < addKey;
    }

    bool cxxlFASTCALL isEqual(UNICODE_String O_Key,UNICODE_String findKey)  const
    {
      //return wcsstr((const wchar_t*)O_Key, (const wchar_t*)findKey) == (const wchar_t*)O_Key;

      const wchar_t *pO_Key = O_Key;
      const wchar_t *pfindKey = findKey;

      while(*pfindKey != L'\0')
      {
        if(*pO_Key == L'\0')
          return false;

        if(*pO_Key != *pfindKey)
          return false;

        ++pO_Key;
        ++pfindKey;
      }

      return true;
    }

  public:
    // Constructor
    Search_Tree(ISpirit *spirit)
      :cxxlObject(spirit), cxxlAVL_Tree<cxxlComposite, UNICODE_String, isUnique>(spirit)
    {
    }
  }m_Search_Tree;


  UNICODE_String m_idName;

  Smart_Ptr<T> Obj_Ptr; // 包裹的物件

  Smart_Ptr<cxxlComposite<T,isUnique> > Parent_Ptr; // 父節點

  // 同層的子物件節點用此串成一串
  cxxlComposite *Next;  // 指向新的
  cxxlComposite *Prev;  // 指向舊的

  // 子物件節點，新加入的在上頭
  // 用此達成依加入順序排列
  cxxlComposite *SubComposite;

  // 放棄持有指定的子結點，pComposite 非 NULL 且是其子點回覆 true
  bool cxxlFASTCALL Release(cxxlComposite *pComposite);

  // 以遞廻的方式複製整個容器
  cxxlComposite<T,isUnique> * cxxlFASTCALL _Clone(cxxlComposite<T,isUnique> *Parent) const;

  // 建立新子節點時用來產生延伸類別的物件
  // 所以延伸別必須覆載
  virtual cxxlComposite<T,isUnique> * cxxlFASTCALL CreateSelf(UNICODE_String idName,ISpirit *spirit) const
  {
    return new cxxlComposite<T,isUnique>(idName,spirit);
  }

  // 延伸類別藉由覆寫此函數以取得 Export() 的匯出結果
  virtual void cxxlFASTCALL Composite_Export(void *def, cxxlComposite<T,isUnique> *BeExported) const
  {
  }

protected:
  CriticalSec csObject;

public:
  // Constructor
  cxxlComposite(const UNICODE_String &idName,ISpirit *spirit = Spirit_Easy)
    :cxxlObject(spirit),m_Search_Tree(spirit),m_idName(idName+COMPOSITERESERVEIDNAME+CreateGuidWStr()),Obj_Ptr(NULL,this),Parent_Ptr(NULL,this)
  {
    SubComposite = Prev = Next = NULL;
  }

  // Destructor
  virtual ~cxxlComposite()
  {
  }



  // 取得子節點的個數
  unsigned long cxxlFASTCALL GetCount() const
  {
    return m_Search_Tree.GetCount();
  }

  // 取得這個節點自己的名稱
  UNICODE_String cxxlFASTCALL GetName() const
  {
    std::wstring temp((const wchar_t*)m_idName);
    size_t found = temp.rfind(COMPOSITERESERVEIDNAME);
    temp.replace(found,1,1,L'\0');
    return UNICODE_String(temp.c_str());
  }





  // 取得這個節點自己包裹的物件
  // 若不存在回覆空物件，可用 Smart_Ptr::isNULL() 檢查
  Smart_Ptr<T> cxxlFASTCALL GetObj() const
  {
    CriticalSecHandle AutoCSH(csObject);
    return Obj_Ptr;
  }


  // 取得指定子節點包裹的物件
  // 若不存在回覆空物件，可用 Smart_Ptr::isNULL() 檢查
  Smart_Ptr<T> cxxlFASTCALL GetObj(const UNICODE_String &idName) const
  {
    CriticalSecHandle AutoCSH(csObject);
    Smart_Ptr<cxxlComposite<T,isUnique> > Composite_Ptr = m_Search_Tree.GetObj(idName+COMPOSITERESERVEIDNAME);
    if(Composite_Ptr.isNULL())
      return NULL;
    else
      return Composite_Ptr->Obj_Ptr;
  }




  // 在這個節點設定物件
  void cxxlFASTCALL SetObj(const Smart_Ptr<T> &Obj)
  {
    csObject.Enter();
    Obj_Ptr = Obj;
    csObject.Leave();
  }

  // 將物件放入一個指定名稱的新子節點
  // 成功傳回放入的節點，失敗傳回空物件，可用 Smart_Ptr::isNULL() 檢查
  Smart_Ptr<cxxlComposite<T,isUnique> > cxxlFASTCALL Add(const Smart_Ptr<T> &Obj, const UNICODE_String &idName);

  // 在指定節點之前，將物件放入一個指定名稱的新子節點
  // 成功傳回放入的節點，失敗傳回空物件，可用 Smart_Ptr::isNULL() 檢查
  Smart_Ptr<cxxlComposite<T,isUnique> > cxxlFASTCALL
    AddPrev(const Smart_Ptr<T> &Obj, const UNICODE_String &idName, const Smart_Ptr<cxxlComposite<T,isUnique> > &Composite);

  // 在指定節點之後，將物件放入一個指定名稱的新子節點
  // 成功傳回放入的節點，失敗傳回空物件，可用 Smart_Ptr::isNULL() 檢查
  Smart_Ptr<cxxlComposite<T,isUnique> > cxxlFASTCALL
    AddNext(const Smart_Ptr<T> &Obj, const UNICODE_String &idName, const Smart_Ptr<cxxlComposite<T,isUnique> > &Composite);





  // 放棄持有指定的子節點
  // pComposite 非 NULL 且是其子節點回覆 true
  bool cxxlFASTCALL Delete(const Smart_Ptr<cxxlComposite<T,isUnique> > &Composite)
  {
    CriticalSecHandle AutoCSH(csObject);
    return Release(Composite);
  }

  // 放棄持有指定的子節點的前一個節點
  // pComposite 及 前一個節點 非 NULL 且是其子節點回覆 true
  bool cxxlFASTCALL DeletePrev(const Smart_Ptr<cxxlComposite<T,isUnique> > &Composite)
  {
    CriticalSecHandle AutoCSH(csObject);
    return (Composite.isNULL())? false:Release(Composite->Prev);
  }

  // 放棄持有指定的子節點的下一個節點
  // pComposite 及 下一個節點 非 NULL 且是其子節點回覆 true
  bool cxxlFASTCALL DeleteNext(const Smart_Ptr<cxxlComposite<T,isUnique> > &Composite)
  {
    CriticalSecHandle AutoCSH(csObject);
    return (Composite.isNULL())? false:Release(Composite->Next);
  }

  // 放棄持有所有子節點
  void cxxlFASTCALL ClearAll();





  // 取得父節點
  // 若不存在回覆空物件，可用 Smart_Ptr::isNULL() 檢查
  Smart_Ptr<cxxlComposite<T,isUnique> > GetParent() const
  {
    return Parent_Ptr;
  }

  // 取得指定名稱的子節點
  // 若不存在回覆空物件，可用 Smart_Ptr::isNULL() 檢查
  Smart_Ptr<cxxlComposite<T,isUnique> >
  cxxlFASTCALL GetComposite(const UNICODE_String &idName) const
  {
    CriticalSecHandle AutoCSH(csObject);
    return m_Search_Tree.GetObj(idName+COMPOSITERESERVEIDNAME);
  }

  // 取得指定的子節點的前一個節點
  // 若不存在回覆空物件，可用 Smart_Ptr::isNULL() 檢查
  Smart_Ptr<cxxlComposite<T,isUnique> >
  cxxlFASTCALL GetCompositePrev(const Smart_Ptr<cxxlComposite<T,isUnique> > &Composite) const
  {
    CriticalSecHandle AutoCSH(csObject);
    if((cxxlComposite<T,isUnique>*)Composite->Parent_Ptr == this)
      return Smart_Ptr<cxxlComposite<T,isUnique> >(Composite->Prev);
    else
      return Smart_Ptr<cxxlComposite<T,isUnique> >(NULL);
  }

  // 取得指定的子節點的下一個節點
  // 若不存在回覆空物件，可用 Smart_Ptr::isNULL() 檢查
  Smart_Ptr<cxxlComposite<T,isUnique> >
  cxxlFASTCALL GetCompositeNext(const Smart_Ptr<cxxlComposite<T,isUnique> > &Composite) const
  {
    CriticalSecHandle AutoCSH(csObject);
    if((cxxlComposite<T,isUnique>*)Composite->Parent_Ptr == this)
      return Smart_Ptr<cxxlComposite<T,isUnique> >(Composite->Next);
    else
      return Smart_Ptr<cxxlComposite<T,isUnique> >(NULL);
  }

  // 將所有子節點放入串列後傳回
  Smart_Ptr<cxxlList<cxxlComposite<T,isUnique> > > cxxlFASTCALL cxxlList_Create() const;

  // 自我複製
  // 傳回相同內容的同類形容器物件
  // 兩個獨立的容器共同擁有相同的物件
  // 但各自的增刪互不影響
  Smart_Ptr<cxxlComposite<T,isUnique> > cxxlFASTCALL Clone()
  {
    return Smart_Ptr<cxxlComposite<T,isUnique> >(_Clone(NULL));
  }

  // 將所有子節點匯出至 Composite_Export()
  // 延伸類別藉由覆寫 Composite_Export() 以取得
  // 注意順序是由後往前匯出
  void cxxlFASTCALL Export(void *def)
  {
    csObject.Enter();

    cxxlComposite<T,isUnique> *P = this->SubComposite;
    while(P)
    {
      Composite_Export(def,P);
      P = P->Prev;
    }

    csObject.Leave();
  }

};

// 以遞廻的方式複製整個容器
template <typename T,bool isUnique>
cxxlComposite<T,isUnique> * cxxlFASTCALL
cxxlComposite<T,isUnique>::_Clone(cxxlComposite<T,isUnique> *Parent) const
{
  CriticalSecHandle AutoCSH(csObject);
  cxxlComposite<T,isUnique> *temp = CreateSelf(GetName(),GetSpirit());
  temp->Obj_Ptr = Obj_Ptr;
  temp->Parent_Ptr = Parent;

  cxxlComposite<T,isUnique> *P = this->SubComposite;
  while(P)
  {
    cxxlComposite<T,isUnique> *subtemp = P->_Clone(temp);
    temp->m_Search_Tree.Add(subtemp,subtemp->m_idName);
    subtemp->Prev = temp->SubComposite;
    temp->SubComposite = subtemp;
    P = P->Prev;
  }

  return temp;
}

// 將所有子節點放入串列後傳回
template <typename T,bool isUnique>
Smart_Ptr<cxxlList<cxxlComposite<T,isUnique> > > cxxlFASTCALL
cxxlComposite<T,isUnique>::cxxlList_Create() const
{
  CriticalSecHandle AutoCSH(csObject);
  cxxlList<cxxlComposite<T,isUnique> > *cxxlList_Temp = new cxxlList<cxxlComposite<T,isUnique> >(this->GetSpirit());

  cxxlComposite<T,isUnique> *P = this->SubComposite;
  while(P)
  {
    cxxlList_Temp->Push_Front(P);
    P = P->Prev;
  }

  return Smart_Ptr<cxxlList<cxxlComposite<T,isUnique> > >(cxxlList_Temp);
}



// 放棄持有所有子節點
template <typename T,bool isUnique>
void cxxlFASTCALL cxxlComposite<T,isUnique>::ClearAll()
{
  CriticalSecHandle AutoCSH(csObject);
  cxxlComposite<T,isUnique> *P = this->SubComposite;
  while(P)
  {
    cxxlComposite<T,isUnique> *PP = P->Prev;
    P->Parent_Ptr.Destroy();
    P->Prev = NULL;
    P->Next = NULL;
    P = PP;
  }
  SubComposite=NULL;
  this->m_Search_Tree.ClearAll();
}


// 放棄持有指定的子結點，pComposite 非 NULL 且是其子節點回覆 true
template <typename T,bool isUnique>
bool cxxlFASTCALL cxxlComposite<T,isUnique>::Release(cxxlComposite *pComposite)
{
  if(pComposite && (cxxlComposite<T,isUnique>*)pComposite->Parent_Ptr == this)
  {
    pComposite->Parent_Ptr.Destroy();
    if(pComposite->Next != NULL)
      pComposite->Next->Prev = pComposite->Prev;
    else
      this->SubComposite = pComposite->Prev;

    if(pComposite->Prev != NULL)
      pComposite->Prev->Next = pComposite->Next;

    this->m_Search_Tree.Delete(pComposite->m_idName);

    return true;
  }
  else
    return false;
}




// 將物件放入一個指定名稱的新子節點
// 成功傳回放入的節點，失敗傳回空物件，可用 Smart_Ptr::isNULL() 檢查
template <typename T,bool isUnique>
Smart_Ptr<cxxlComposite<T,isUnique> > cxxlFASTCALL
cxxlComposite<T,isUnique>::Add(const Smart_Ptr<T> &pObj, const UNICODE_String &idName)
{
  if( wcsstr((const wchar_t *)idName, COMPOSITERESERVEIDNAME) != 0)
    return NULL;

  CriticalSecHandle AutoCSH(csObject);

  if(isUnique && m_Search_Tree.GetObj(idName+COMPOSITERESERVEIDNAME).isNULL() == false)
    return NULL;

  cxxlComposite<T,isUnique> *temp = CreateSelf(idName,GetSpirit());
  temp->Obj_Ptr = pObj;
  temp->Parent_Ptr = this;

  m_Search_Tree.Add(temp,temp->m_idName);
  temp->Prev = SubComposite;
  if(SubComposite != NULL)
    SubComposite->Next = temp;
  SubComposite = temp;

  return Smart_Ptr<cxxlComposite<T,isUnique> >(temp);
}

// 在指定節點之前，將物件放入一個指定名稱的新子節點
// 成功傳回放入的節點，失敗傳回空物件，可用 Smart_Ptr::isNULL() 檢查
template <typename T,bool isUnique>
Smart_Ptr<cxxlComposite<T,isUnique> > cxxlFASTCALL
cxxlComposite<T,isUnique>::AddPrev(const Smart_Ptr<T> &pObj, const UNICODE_String &idName, const Smart_Ptr<cxxlComposite<T,isUnique> > &Composite)
{
  if((cxxlComposite<T,isUnique>*)Composite->Parent_Ptr == this)
  {
    if( wcsstr((const wchar_t *)idName, COMPOSITERESERVEIDNAME) != 0 )
      return NULL;

    CriticalSecHandle AutoCSH(csObject);

    if(isUnique && m_Search_Tree.GetObj(idName+COMPOSITERESERVEIDNAME).isNULL() == false)
      return NULL;

    cxxlComposite<T,isUnique> *temp = CreateSelf(idName,GetSpirit());
    temp->Obj_Ptr = pObj;
    temp->Parent_Ptr = this;

    m_Search_Tree.Add(temp,temp->m_idName);
    if(Composite->Prev != NULL)
      Composite->Prev->Next = temp;
    temp->Prev = Composite->Prev;
    temp->Next = Composite;
    Composite->Prev = temp;
    return Smart_Ptr<cxxlComposite<T,isUnique> >(temp);
  }
  else
    return Smart_Ptr<cxxlComposite<T,isUnique> >((cxxlComposite<T,isUnique> *)NULL);
}

// 在指定節點之後，將物件放入一個指定名稱的新子節點
// 成功傳回放入的節點，失敗傳回空物件，可用 Smart_Ptr::isNULL() 檢查
template <typename T,bool isUnique>
Smart_Ptr<cxxlComposite<T,isUnique> > cxxlFASTCALL
cxxlComposite<T,isUnique>::AddNext(const Smart_Ptr<T> &pObj, const UNICODE_String &idName, const Smart_Ptr<cxxlComposite<T,isUnique> > &Composite)
{
  if((cxxlComposite<T,isUnique>*)Composite->Parent_Ptr == this)
  {
    if( wcsstr((const wchar_t *)idName, COMPOSITERESERVEIDNAME) != 0 )
      return NULL;

    CriticalSecHandle AutoCSH(csObject);

    if(isUnique && m_Search_Tree.GetObj(idName+COMPOSITERESERVEIDNAME).isNULL() == false)
      return NULL;

    cxxlComposite<T,isUnique> *temp = CreateSelf(idName,GetSpirit());
    temp->Obj_Ptr = pObj;
    temp->Parent_Ptr = this;

    m_Search_Tree.Add(temp,temp->m_idName);
    if(Composite->Next != NULL)
      Composite->Next->Prev = temp;
    else
      SubComposite = temp;

    temp->Next = Composite->Next;
    temp->Prev = Composite;
    Composite->Next = temp;
    return Smart_Ptr<cxxlComposite<T,isUnique> >(temp);
  }
  else
    return Smart_Ptr<cxxlComposite<T,isUnique> >((cxxlComposite<T,isUnique> *)NULL);
}

// 匯出 名稱不可重複 包裹 UNICODE 字串的 cxxlComposite
extern CXXLCONTAINER_DLLEXPORT void cxxlFASTCALL UniqueTxtCompositeExport(std::wostream &wout, const Smart_Ptr<cxxlComposite<string_wrapper<wchar_t>,true> > &TxtComposite);

// 匯出 名稱可重複 包裹 UNICODE 字串的 cxxlComposite
extern CXXLCONTAINER_DLLEXPORT void cxxlFASTCALL NonUniqueTxtCompositeExport(std::wostream &wout, const Smart_Ptr<cxxlComposite<string_wrapper<wchar_t>,false> > &TxtComposite);

/*
template <typename T>
void cxxlFASTCALL TxtCompositeExport(std::wostream &wout, const Smart_Ptr<T> &TxtComposite_Arg)
{
  Smart_Ptr<cxxlComposite<string_wrapper<wchar_t>,true> > TxtComposite_Ptr = static_cast<cxxlComposite<string_wrapper<wchar_t>,true> *>((T*)TxtComposite_Arg);
  if(TxtComposite_Ptr.isNULL() == false)
    UniqueTxtCompositeExport(wout, TxtComposite_Ptr);
  else
    NonUniqueTxtCompositeExport(wout, static_cast<cxxlComposite<string_wrapper<wchar_t>,false> *>((T*)TxtComposite_Arg));
}
*/


// 匯入 建立 包裹 UNICODE 字串 名稱不可重複的 cxxlComposite 後傳回，須藉由 tempUniqueTxtComposite_Arg 指定一個空的 cxxlComposite 樣版，將用它產生要傳回的 cxxlComposite 物件
// 須是 cxxlComposite<string_wrapper<wchar_t>,true> 或其延伸類別
// 若有錯誤回傳 NULL
extern CXXLCONTAINER_DLLEXPORT Smart_Ptr<cxxlComposite<string_wrapper<wchar_t>,true> > cxxlFASTCALL UniqueTxtCompositeImport(
  std::wistream &TLC,
  const Smart_Ptr<cxxlComposite<string_wrapper<wchar_t>,true> > &tempUniqueTxtComposite_Arg = new cxxlComposite<string_wrapper<wchar_t>,true>(L"tempComposite", Spirit_Easy));

// 匯入 建立 包裹 UNICODE 字串 名稱可重複的 cxxlComposite 後傳回，須藉由 tempNonUniqueTxtComposite_Arg 指定一個空的 cxxlComposite 樣版，將用它產生要傳回的 cxxlComposite 物件
// 須是 cxxlComposite<string_wrapper<wchar_t>,false> 或其延伸類別
// 若有錯誤回傳 NULL
extern CXXLCONTAINER_DLLEXPORT Smart_Ptr<cxxlComposite<string_wrapper<wchar_t>,false> > cxxlFASTCALL NonUniqueTxtCompositeImport(
  std::wistream &TLC,
  const Smart_Ptr<cxxlComposite<string_wrapper<wchar_t>,false> > &tempNonUniqueTxtComposite_Arg = new cxxlComposite<string_wrapper<wchar_t>,false>(L"tempComposite", Spirit_Easy));



}   /* namespace CxxlMan */
#endif
